#ifndef BSPMODEL_H
#define BSPMODEL_H

#define FACE_POLYGON 1

#include <windows.h>
#include <iostream>
#include "vector.h"
#include "vector2D.h"
#include "gl\gl.h"
#include "gl\glu.h"
#include "gl\glaux.h"
#include "gl\glut.h"
#include <mmsystem.h>
#include "main.h"

enum lumps
{
	ENTITIES = 0,				// Stores player/object positions
    TEXTURES,					// Stores texture information
    SPLITTING_PLANES,			// Stores the splitting planes
    NODES,						// Stores the BSP nodes
    LEAFS,						// Stores the leafs of the nodes
    LEAF_FACES,					// Stores the leaf's indices into the faces
    LEAF_BRUSHES,				// Stores the leaf's indices into the brushes
    MODELS,						// Stores the info of world models
    BRUSHES,					// Stores the brushes info (for collision)
    BRUSH_SIDES,				// Stores the brush surfaces info
    VERTICES,					// Stores the level vertices
    INDICES,					// Stores the level indices
    SHADERS,					// Stores the shader files (blending, anims..)
    FACES,						// Stores the faces for the level
    LIGHT_MAPS,					// Stores the lightMaps for the level
    LIGHT_VOLUMES,				// Stores extra world lighting information
    VISIBILITY_DATA,			// Stores PVS and cluster info (visibility)
    MAX_LUMPS					// A constant to store the number of lumps
};

struct SimpleVector
{
	int x, y, z;
};
struct BSPTexture
{
	char textureName[64];
	int flags;
	int contents;
};

struct BSPFace
{
	int textureID;
	int effect;
	int type;
	int startVertIndex;
	int numberOfVertices;
	int startIndex;
	int numberOfIndices;
	int lightMapID;
	int mapCorner[2];
	int mapSize[2];
	Vector mapPosition;
	Vector mapVecs[2];
	Vector normal;
	int size[2];
};

struct BSPVertex
{
	Vector position;
	Vector2D textureCoordination;
	Vector2D lightMapCoordination;
	Vector normal;
	byte color[4];
};

struct BSPHeader
{
	char BSPID[4];	// should always be 'IBSP'
	int version;	// should be 0x2e for Quake 3 files
};

struct BSPLump
{
	int offset;
	int length;
};

struct BSPLightMap
{
    byte imageBits[128][128][3];
};

struct BSPNode
{
    int plane;
    int front;
    int back;
    SimpleVector min;
    SimpleVector max;
}; 

struct BSPLeaf
{
    int cluster;
    int area;
    SimpleVector min;
    SimpleVector max;
    int leafFace;
    int numberOfLeafFaces;
    int leafBrush;
    int numberOfLeafBrushes;
}; 

struct BSPPlane
{
    Vector normal;
    float d;
};

struct BSPVisData
{
	int numberOfClusters;
	int bytesPerCluster;
	byte *bitsets;
};

class Bitset
{
public:
	Bitset() : bits(0), size(0) {}

	~Bitset()
	{
		if(bits)
		{
			delete bits;
			bits = NULL;
		}
	}

	void resize(int count)
	{
		size = count / 32 + 1;
		if(bits)
		{
			delete bits;
			bits = 0;
		}

		bits = new unsigned int[size];
		clearAll();
	}

	void set(int i)
	{
		bits[i >> 5] |= (1 << (i & 31));
	}

	int on(int i)
	{
		return bits[i >> 5] & (1 << (i & 31));
	}

	void clear(int i)
	{
		bits[i >> 5] &= ~(1 << (i & 31));
	}

	void clearAll()
	{
		memset(bits, 0, sizeof(unsigned int) * size);
	}
	
private:
	unsigned int *bits;
	int size;
};

class BSPModel
{
public:
	BSPModel();
	~BSPModel();

	void changeGamma(byte *image, int size, float factor);
	void createLightmapTexture(UINT &texture, byte *imageBits, int width, int height);
	bool loadBSP(const char *fileName);
	void renderLevel(const Vector &position);
	void destroy();

private:
	int numberOfVertices;
	int numberOfFaces;
	int numberOfIndices;
	int numberOfTextures;
	int numberOfLightMaps;
	int numberOfNodes;
	int numberOfLeafs;
	int numberOfLeafFaces;
	int numberOfPlanes;

	int *indices;
	BSPVertex *vertices;
	BSPFace *faces;
	BSPNode *nodes;
	BSPLeaf *leafs;
	BSPPlane *planes;
	int *leafFaces;
	BSPVisData clusters;

	UINT textures[MAX_TEXTURES];
	UINT lightMaps[MAX_TEXTURES];

	Bitset facesDrawn;

	void findTextureExtension(char *fileName);
	void renderFace(int faceIndex);
	int isClusterVisible(int current, int test);
	int findLeaf(const Vector &position);
};

#endif //BSPMODEL_H